package picasa;

import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.*;
/*implements tuning, contrast and color manipulation*/
public class TuningEffects extends Frame {
	BufferedImage bImage = null;
	String className;
	String interfaceName;
	double contrast;
	double brightness;
	int red;
	int blue;
	int green;
	
	public TuningEffects(String interfaceName, double contrast, double brightness){
	
		this.interfaceName = interfaceName;
		this.contrast = contrast;
		this.brightness=brightness;
		
	}
	public TuningEffects (String interfaceName, int red, int blue, int green){
		
		this.interfaceName = interfaceName;
		this.red = red;
		this.blue = blue;
		this.green = green;
		
	}
	//this method deals with color, brightness, contrast
	public void Tuning(BufferedImage newImage){
		int imgCols;//Number of horizontal pixels
		int imgRows;//Number of rows of pixels
		
		//References to arrays that store pixel data.
		int[][][] threeDPix;
		int[][][] threeDPixMod;
		int[] oneDPix;
		//Reference to the image processing object.
		
		
		Image image= null;
		//Gets the width and height of the image
		imgCols = newImage.getWidth();
	    imgRows = newImage.getHeight();
	    
        // Create a 1D array object to receive the
	    // pixel representation of the image
	    oneDPix = new int[imgCols * imgRows];
	    
	    //Convert the BufferedImage to numeric pixel representation.
	    WritableRaster raster = newImage.getRaster();
	    
	    //DataBuffer dataBufferInt = raster.getDataBuffer();
	    //Raster raster = newImage.getData();
	    DataBuffer db =  raster.getDataBuffer();
	    DataBufferInt dbi = (DataBufferInt)db;
	    oneDPix = dbi.getData();
	    newImage = null;
	    //Convert the pixel byte data in the 1D
	    // array to int data in a 3D array to
	    // make it easier to work with the pixel
	    // data later.  Recall that pixel data is
	    // unsigned byte data and Java does not
	    // support unsigned arithmetic.
	    // Performing unsigned arithmetic on byte
	    // data is particularly cumbersome.
	    threeDPix = convertToThreeDim(oneDPix,imgCols,imgRows);
	    //Instantiate a new object of the image
	    // processing class.  Note that this
	    // object is instantiated using the
	    // newInstance method of the class named
	    // Class.  This approach does not support
	    // the use of a parameterized
	    // constructor.
	    try{
	    	
	    	if (interfaceName.equals("ImageInterface")){
	    		ImageInterface imageProcessingObject;
	    		imageProcessingObject = (ImageInterface)Class.forName("picasa.BrightnessAlg").newInstance();
	    	 threeDPixMod = imageProcessingObject.processImg(threeDPix,imgRows,imgCols, contrast, brightness);
	    	}else{
	    		ColorInterface imageProcessingObject;
	    		imageProcessingObject = (ColorInterface)Class.forName("picasa.ColorAlg").newInstance();
	    		threeDPixMod = imageProcessingObject.processImg(threeDPix,imgRows,imgCols, red, blue, green);
	    	}	
          //Pass a 3D array of pixel data to the
          // processing object and get a modified
          // 3D array of pixel data back.  The
          // creation of the 3D array of pixel
          // data is explained later.
         
          //Convert the modified pixel data to a
          // 1D array of pixel data.  The 1D
          // array is explained later.
          threeDPix = null;
          oneDPix = convertToOneDim(threeDPixMod,imgCols,imgRows);
          //Use the createImage() method to
          // create a new image from the 1D array
          // of pixel data.
          image = createImage(new MemoryImageSource(imgCols,imgRows,oneDPix,0,imgCols));
	      //Converts the image to a BufferedImage
          bImage = new BufferedImage(imgCols,imgRows, BufferedImage.TYPE_INT_ARGB);
          Graphics g2d = bImage.getGraphics();
	      g2d.drawImage(image,0,0,null);
	    }catch(Exception e){
	      System.out.println(e);
	    }//end catch
	}//end of method
	
	public BufferedImage returnImage(){
		return bImage;
		
	}

	int[][][] convertToThreeDim(
	          int[] oneDPix,int imgCols,int imgRows){
	    //Create the new 3D array to be populated
	    // with color data.
	    int[][][] data =
	                    new int[imgRows][imgCols][4];

	    for(int row = 0;row < imgRows;row++){
	      //Extract a row of pixel data into a
	      // temporary array of ints
	      int[] aRow = new int[imgCols];
	      for(int col = 0; col < imgCols;col++){
	        int element = row * imgCols + col;
	        aRow[col] = oneDPix[element];
	      }//end for loop on col

	      //Move the data into the 3D array.  Note
	      // the use of bitwise AND and bitwise right
	      // shift operations to mask all but the
	      // correct set of eight bits.
	      for(int col = 0;col < imgCols;col++){
	        //Alpha data
	        data[row][col][0] = (aRow[col] >> 24)
	                                          & 0xFF;
	        //Red data
	        data[row][col][1] = (aRow[col] >> 16)
	                                          & 0xFF;
	        //Green data
	        data[row][col][2] = (aRow[col] >> 8)
	                                          & 0xFF;
	        //Blue data
	        data[row][col][3] = (aRow[col])
	                                          & 0xFF;
	      }//end for loop on col
	    }//end for loop on row
	    return data;
	  }//end convertToThreeDim
	
	  //The purpose of this method is to convert the
	  // data in the 3D array of ints back into the
	  // 1d array of type int.  This is the reverse
	  // of the method named convertToThreeDim.
	  int[] convertToOneDim(
	         int[][][] data,int imgCols,int imgRows){
	    //Create the 1D array of type int to be
	    // populated with pixel data, one int value
	    // per pixel, with four color and alpha bytes
	    // per int value.
	    int[] oneDPix = new int[
	                          imgCols * imgRows * 4];

	    //Move the data into the 1D array.  Note the
	    // use of the bitwise OR operator and the
	    // bitwise left-shift operators to put the
	    // four 8-bit bytes into each int.
	    for(int row = 0,cnt = 0;row < imgRows;row++){
	      for(int col = 0;col < imgCols;col++){
	        oneDPix[cnt] = ((data[row][col][0] << 24)
	                                   & 0xFF000000)
	                     | ((data[row][col][1] << 16)
	                                   & 0x00FF0000)
	                      | ((data[row][col][2] << 8)
	                                   & 0x0000FF00)
	                           | ((data[row][col][3])
	                                   & 0x000000FF);
	        cnt++;
	      }//end for loop on col

	    }//end for loop on row

	    return oneDPix;
	  }//end convertToOneDim
}
